Comment configurer un serveur de messagerie auto-hébergé Maddy
Table des matières
Comment fonctionne le courrier électronique
Choisissez le serveur de messagerie
Bien qu’envoyer/recevoir des e-mails soit facile, gérer un service de messagerie complet est très difficile. L'une des raisons de cette difficulté est que le courrier électronique est un système fédéral, chaque message doit être transmis d'un serveur à un autre serveur. De nos jours, les gens ne peuvent plus transmettre leur message directement au serveur du destinataire. Tous ces serveurs de messagerie utilisent le Simple Mail Transfer Protocol (SMTP) pour communiquer.
Lorsque le destinataire acceptera le courrier, celui-ci sera enregistré sur le serveur. L'utilisateur doit utiliser un autre protocole comme POP3 ou IMAP pour se connecter au serveur afin de vérifier ses messages. Chez certains grands fournisseurs de services de messagerie, les services SMTP et POP3/IMAP sont distribués sur des serveurs différents, ce qui complique encore davantage le système.
Ainsi, la grande image de la livraison des e-mails est la suivante :
mx.example.com mx.example.net
┌────┐ ┌───┐ SMTP ┌───┐ ┌────┐
│IMAP│◄────│MX1│◄───────────►│MX2│──►│IMAP│
└─┬──┘ └───┘ └───┘ └──┬─┘
│ ▲ ▲ │ Server
-------------│----------│-----------------│--------│---------------------
│IMAP │ │ │IMAP Local
▼ │ │ ▼
┌───────────┐ │ │ ┌─────────┐
┌──►│Thunderbird│────┘ SMTP Submission └────┤AppleMail│─────┐
│ └───────────┘ └─────────┘ │
│ ▼
Alice Bob
Examinons le processus par lequel Alice envoie du courrier de alice@example.com à bob@example.net
Tout d'abord, Alice ouvre son client de messagerie Thunderbird, connu sous le nom de Mail User Agent (MUA). Et puis, elle compose le contenu de son courrier. Une fois terminé, elle clique sur le bouton envoyer. Et le MUA essaie de se connecter à l'agent de transfert de courrier (MTA), MX1, en utilisant le protocole SMTP et de lui soumettre son courrier électronique. Dans cette procédure, le MTA doit autoriser le MUA en laissant le MUA proposer le nom d'utilisateur et le mot de passe. Après l'autorisation, le MUA utilise le protocole SMTP pour soumettre le courrier.
Une fois la soumission du courrier terminée, le MTA commence à essayer de remettre le courrier au MTA de Bob. Le MX1 recherche d'abord l'enregistrement MX DNS du domaine example.net, qui est le domaine de l'adresse e-mail de Bob. Et il obtiendra une liste de noms d’hôtes avec leur poids. MX1 tentera de se connecter à l'hôte en fonction de son poids par ordre croissant. Ainsi, MX1 se connecte à MX2 en utilisant le port TCP 25. MX1 indique au MX2 qu'il souhaite envoyer un courrier de alice@example.com à bob@example.net . Comme MX2 est le MTA de example.net, il sait que bob@example.net est un compte de messagerie légal, il doit donc recevoir ce courrier.
Voici les MXenregistrements de gmail.com:
drill mx gmail.com
;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 64117
;; flags: qr rd ra ; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;; gmail.com. IN MX
;; ANSWER SECTION:
gmail.com. 3389 IN MX 30 alt3.gmail-smtp-in.l.google.com.
gmail.com. 3389 IN MX 10 alt1.gmail-smtp-in.l.google.com.
gmail.com. 3389 IN MX 40 alt4.gmail-smtp-in.l.google.com.
gmail.com. 3389 IN MX 20 alt2.gmail-smtp-in.l.google.com.
gmail.com. 3389 IN MX 5 gmail-smtp-in.l.google.com.
;; ...
Cependant, afin d'éviter les spams, MX1 doit effectuer certaines vérifications pour s'assurer que MX1 est le MTA légal du domaine de messagerie example.com. Il y a plusieurs tâches à accomplir.
Lorsque MX1 établit la liaison TCP avec MX2, son premier message ressemble à
EHLO mx.example.com
Et ce message EHLO indique à MX2 que le nom d'hôte de l'expéditeur est mx.example.com. MX2 peut rechercher l'enregistrement PTR en fonction de l'adresse IP du serveur et vérifier si la réponse correspond au nom d'hôte de l'expéditeur signalé par EHLO. C'est pourquoi nous devons établir le bon enregistrement PTR.
Nous pouvons utiliser le drillpour interroger l'enregistrement PTR :
drill -x 8.8.4.4
;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 3912
;; flags: qr rd ra ; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;; 4.4.8.8.in-addr.arpa. IN PTR
;; ANSWER SECTION:
4.4.8.8.in-addr.arpa. 58104 IN PTR dns.google.
;; ...
La réponse indique que l'adresse 8.8.4.4 est associée au domaine dns.google.
Si le PTR de l'expéditeur ne pointe pas vers son nom d'hôte, il peut s'agir de l'expéditeur du spam.
Cependant, autant que je sache, les MTA modernes ont tendance à ne pas effectuer cette recherche DNS inversée, car cela imposerait une charge trop lourde à la zone de in-addr.arpa et ip6.arpa, ce qui ralentirait la livraison du courrier. Mais il est toujours recommandé de définir l'enregistrement PTR pour qu'il remplisse le MTA qui effectue toujours une telle vérification.
Si le MTA destinataire ne vérifie pas l’enregistrement PTR, comment pourrait-il détecter l’expéditeur du spam ? La réponse est l'enregistrement SPF. Le MTA moderne recherchera un autre enregistrement TXT avec une structure spécifique SPF. Et voici sur un simple enregistrement SPF,
drill TXT google.com|grep spf
google.com. 1319 IN TXT "v=spf1 include:_spf.google.com ~all"
Le préfixe v=spf1 signifie qu'il s'agit d'un enregistrement SPF. Le include:_spf.google.com signifie que toutes les règles SPF doivent rechercher à partir de l'enregistrement SPF du domaine _spf.google.com. Et enfin ~all, si l'expéditeur ne peut pas remplir la règle SPF, l'e-mail envoyé doit être placé dans la corbeille.
Creusons le SPF de _spf.google.com:
"v=spf1 include:_netblocks.google.com include:_netblocks2.google.com include:_netblocks3.google.com ~all"
Il comprend toujours trois autres listes SPF. Nous recherchons donc à nouveau les enregistrements SPF des deux premiers domaines :
"v=spf1 ip4:35.190.247.0/24 ip4:64.233.160.0/19 ip4:66.102.0.0/20 ip4:66.249.80.0/20 ip4:72.14.192.0/18 ip4:74.125.0.0/16 ip4:108.177.8.0/21 ip4:173.194.0.0/16 ip4:209.85.128.0/17 ip4:216.58.192.0/19 ip4:216.239.32.0/19 ~all"
"v=spf1 ip6:2001:4860:4000::/36 ip6:2404:6800:4000::/36 ip6:2607:f8b0:4000::/36 ip6:2800:3f0:4000::/36 ip6:2a00:1450:4000::/36 ip6:2c0f:fb50:4000::/36 ~all"
L'enregistrement SPF de _netblocks.google.com spécifie plusieurs blocs d'adresses IPv4 et _netblocks2s pécifie plusieurs blocs d'adresses IPv6. Toutes les adresses appartenant à ces blocs sont autorisées à envoyer du courrier depuis le domaine de google.com. Le courrier provenant d’une adresse IP non répertoriée dans les enregistrements SPF sera supprimé.
Le SPF est plus léger que le PTR, car il n'est pas nécessaire de contacter le propriétaire de l'adresse IP pour modifier les enregistrements PTR. Et la solution SPF est plus efficace que le PTR. Toutefois, ce n’est pas la solution finale. Parce qu’il existe encore des méthodes pour détourner l’adresse IP pour envoyer du spam. Par exemple, certains mauvais FAI peuvent utiliser le protocole BGP pour détourner une adresse IP qui ne leur appartient pas. Une solution ultra est donc nécessaire. Et ce sont les signatures de courrier identifiées DomainKeys (DKIM).
L'idée principale de DKIM est de rendre publique une clé publique de signature à l'aide d'un enregistrement DKIM spécial. Chaque courrier envoyé à partir d'un MTA sera accompagné de la signature numérique avec la clé privée correspondante, et le MTA destinataire pourra ensuite rechercher la clé de signature publique de l'expéditeur pour compléter la signature. Seule la vérification de la signature DKIM réussie peut permettre au courrier d'être accepté.
Voici un exemple d'enregistrement DKIM :
drill txt default._domainkey.example.com
;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 50686
;; flags: qr rd ra ; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;; default._domainkey.lvht.net. IN TXT
;; ANSWER SECTION:
default._domainkey.example.org. 300 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAA..."
Et voici un exemple de signature DKIM :
DKIM-Signature: a=rsa-sha256; bh=iQ/2DHA4xYuzNkuty4mmtgXpGyW0lOv+tDU9bZ5y9zA=; c=relaxed/relaxed; d=example.com; h=Subject:Subject:Sender:To:To:Cc:From:From:Date:Date:MIME-Version:Content-Type:Content-Transfer-Encoding:Reply-To:In-Reply-To:Message-Id:Message-Id:References:Autocrypt:Openpgp; i=@example.org; s=default; t=1698495966; v=1; x=1698927966; b=fsRwrjAXpqNbPhB...
Comment calculer cette signature sort du cadre de cet article. Mais il faut remarquer le s=default et d=example.com qui sera utilisé pour récupérer l'enregistrement DKIM. Dans cet exemple, le MTA destinataire recherchera le DKIM de default._domainkey.example.com, puis vérifiera la signature.
Grâce au DKIM, le fournisseur de services de messagerie supprimera totalement la dépendance vis-à-vis du FAI de bas niveau et garantira qu'aucun courrier ne pourra être envoyé depuis ses propres infrastructures.
Bien que le MTA du destinataire puisse gérer lui-même l'e-mail en fonction du SPF ou du DKIM, il existe toujours un mécanisme permettant à l'expéditeur de modifier le comportement des destinataires. Il s'agit ici de l'authentification, du reporting et de la conformité des messages basés sur le domaine (DMARC) .
Le DMARC est un peu compliqué, et je ne vais pas entrer dans les détails. L'idée principale est d'utiliser DNS pour publier un enregistrement DMARC TXT spécial comme
_dmarc.example.org. TXT "v=DMARC1; p=quarantine; ruf=mailto:postmaster@example.org"
Le label de l'enregistrement TXT est _dmarc. Le v=DMARC1 est corrigé actuellement. Les p=moyens la politique. Si la vérification SPF ou DKIM échoue, le côté destinataire doit prendre des mesures conformément à la politique DMARC. Trois valeurs sont définies :
•none : le propriétaire du domaine expéditeur demande qu'aucune mesure spécifique ne soit prise concernant la livraison des messages. Le MTA destinataire doit donc prendre des mesures de manière indépendante.
•quarantine : le destinataire doit supprimer les e-mails suspects.
•reject : le destinataire doit rejeter tous les e-mails suspects.
Le ruf=mailto:postmaster@example.org nécessite que le destinataire signale les informations d'échec au courrier de postmaster@example.org . Pour que l'opérateur expéditeur trouve le problème le plus rapidement possible.
Lorsque Bob voudra consulter sa boîte aux lettres, il l'ouvrira MUA. Et puis, le MUA connectera son serveur IMAP pour vérifier le nouveau message. S'il y a de nouveaux e-mails, le MUA les affichera dans son interface utilisateur et les montrera à Bob.
C'est la procédure de transfert totale. Même si c'est très compliqué, la conception en texte brut de SMTP/IMAP aggrave le système. Aux débuts d’Internet, toutes les données sont transférées en texte brut, ce qui signifie qu’elles peuvent être reniflées par le FAI. Le système de messagerie d’origine présente donc d’énormes risques de sécurité. Afin de résoudre ce problème, TLS ou STARTTLS ont été introduits, ce qui rend le système encore plus compliqué.
Les soumissions SMTP et SMTP utilisaient toutes deux le TCP en texte brut sur le port 25. Le protocole POP3 simple utilise le port 110 sur TCP et IMAP utilise le port 143 sur TCP. Nous voulons introduire TLS pour protéger le trafic de messagerie, ils attribuent simplement de nouveaux ports dédiés pour la version TLS. Ils ont donc laissé la version TLS de POP3 utiliser le port 995 de TCP et la version TLS d'IMAP utiliser 993. Pour SMTP avec TLS, le port 465 est attribué.
La solution fonctionne mais avec un seul problème, il n'y a que 1024 ports réservés à des services bien connus. Si tous les protocoles nécessitent un port supplémentaire pour la connexion de la version TLS, les ports bien connus seront très vite épuisés. Une autre solution, STARTTLS, a donc été introduite. Dans STARTTLS, lorsque le côté client crée un nouveau lien TCP, le côté serveur indiquera s'il prend en charge TLS. Si tel est le cas, le client tentera de mettre à niveau le lien TCP en texte brut actuel vers la session TLS. Grâce à cette conception, tous les protocoles de texte en clair existants bénéficient de cette fonctionnalité sur certains ports.
Le STARTTLS a également un problème crucial, l’attaque de l’homme du milieu (MITM). Si le FAI souhaite détourner le trafic de messagerie, il peut intercepter la réponse STARTTLS du serveur et laisser le client utiliser uniquement le transport en texte brut. Afin de résoudre ce problème, le SMTP MTA Strict Transport Security (MTA-STS) a été conçu.
L'idée principale de MTA-STS est d'utiliser un enregistrement TXT spécial pour indiquer que le domaine du destinataire dispose d'une politique STARTTLS, qui est publiée par un point de terminaison HTTPS bien connu.
L'étiquette DNS est _mta-sts. Si nous voulons un MTA-STS public, nous devons ajouter l'enregistrement TXT suivant au DNS :
_mta-sts.example.com. IN TXT "v=STSv1; id=20160831085700Z;"
Le v=STSv1 est une valeur fixe. Et la valeur de id= est la version de la stratégie, grâce à laquelle l'expéditeur peut déterminer s'il est nécessaire d'actualiser la stratégie. Une fois que l'expéditeur a obtenu l'enregistrement MTA-STS, il récupère la véritable politique à partir de l'URL suivante :
https://mta-sts.example.com/.well-known/mta-sts.txt
Et son contenu ressemble à :
version: STSv1
mode: enforce
max_age: 604800
mx: mx1.example.org
mx: mx2.example.org
Le version: STSv1 est corrigé actuellement. Le mode: a plusieurs valeurs, mais nous devrions le définir sur enforcel equel forcer tous les MTA d'envoi à utiliser le STARTTLS sans condition. Le max_age: indique la durée maximale pendant laquelle l'expéditeur doit mettre la stratégie en cache. Et la clé mx indique les hôtes MTA autorisés à recevoir des e-mails pour le domaine de destination, ce qui remplacera l'enregistrement MX du DNS.
Semblable à DMARC, il existe également un mécanisme de rapport d’échec pour MTA-STS. Il s'agit du TLSRPT. Le MTA-STS est utilisé pour que l'expéditeur envoie un e-mail au destinataire. S'il y a une attaque MITM, le récepteur ne peut pas la détecter. Ainsi, l'expéditeur peut publier l'enregistrement TLSRPT pour lui demander de signaler l'utilisation de STARTTLS.
Voici un exemple de TLSRPT :
_smtp._tls.example.org. TXT "v=TLSRPTv1;rua=mailto:postmaster@example.org"
Si l'expéditeur prend en charge TLSRPT, il enverra les statistiques de réussite ou d'échec de MTA-STS à la boîte aux lettres du destinataire. Ainsi, le récepteur peut détecter le problème le plus rapidement possible.
Enfin, nous avons terminé tous les détails sur le fonctionnement de l'e-mail. Il est temps de faire les vraies configurations.
Nous avons besoin d’au moins un ordinateur ou VPS avec une adresse IP statique.
Seul le propriétaire de l'adresse IP ou du VPS peut modifier cet enregistrement.
Avant de soumettre la demande, vous devez choisir un nom pour votre serveur de messagerie. Il est recommandé d'utiliser un nom comme mx1.example.org car le mx signifie échange de courrier.
Il faut demander ou valider la possibilité d’envoyer des e-mails vers Internet en utilisant le port TCP sortant 25.
STARTTLS et HTTPS nécessitent un certificat SSL. Nous pouvons utiliser acme.sh pour obtenir des certificats gratuits.
Avant d'exécuter acme.sh, nous devons d'abord configurer l'enregistrement A/AAAA pour le domaine mx1.example.org.
Je choisis ce domaine comme nom d'hôte de mon MTA. IPv4 et IPv6 doivent être pris en charge. Et puis créez un enregistrement CNAME pour le _mta-sts.example.org domaine mx1.example.org.
Il n’est donc pas nécessaire de configurer l’A/AAAA à plusieurs reprises.
Nous devons maintenant installer le fichier acme.sh en tant que racine :
Afin de proposer la politique MTA-STS et d'émettre un certificat, nous devons installer un serveur HTTP. Je choisis le Nginx.
apt install nginx # (debian) et pacman -S nginx (archlinux)
Après l'installation de Nginx, nous pouvons utiliser le mode webroot pour émettre un certificat. Je préfère émettre différents certificats pour différents domaines, je procède donc comme suit :
Les certificats sont stockés à l'emplacement de /root/.acme.sh/{mx1,mta-sts}.example.org.
Et puis nous ajoutons crontab pour réémettre automatiquement ces certificats :
5 21 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null && /usr/sbin/nginx -s reload
Je recommande le Maddy Mail Server. Il est développé par le Golang. Il peut envoyer des messages via SMTP (fonctionne comme MTA), accepter des messages via SMTP (fonctionne comme MX) et stocker des messages tout en y donnant accès via IMAP. En plus de cela, il implémente des protocoles auxiliaires obligatoires pour assurer une sécurité raisonnable du courrier électronique (DKIM, SPF, DMARC, DANE, MTA-STS).
Il remplace Postfix, Dovecot, OpenDKIM, OpenSPF, OpenDMARC et bien d'autres par un seul démon avec une configuration uniforme et un coût de maintenance minimal.
Léger et sécurisé, et prenant en charge la plate-forme ARM, j'ai donc choisi d'utiliser le serveur de messagerie Maddy comme serveur de messagerie auto-hébergé.
Installez d'abord la chaîne d'outils C et Make :
Installez ensuite la dernière chaîne d'outils Go (j'utilise le arm64) :
Clonez le code source :
Sélectionnez la version appropriée à construire
La v0.7.0 a quelques bugs pour STARTTLS, j'utilise actuellement la branche master.
Enfin, construisez et installez :
Dans le répertoire build, vous verrez les fichiers suivants :
build
├── maddy
├── maddy.conf
└── systemd
├── maddy.service
└── maddy@.service
Copiez systemd/*.service dans /etc/systemd/system et copiez maddy.conf dans /etc/maddy/, puis copiez maddy dans /usr/local/bin.
Ajoutez l'utilisateur maddy pour exécuter le processus du serveur maddy :
Recharger le service systemd
Définissez le nom d'hôte et le domaine de messagerie de maddy.conf :
; used in the EHLO request
$(hostname) = mx1.example.org
$(primary_domain) = example.org
; if you have multiple domains
$(local_domains) = $(primary_domain) example.com
Mise en place du certificat TLS du maddy.conf :
tls file /root/.acme.sh/$(hostname)_ecc/fullchain.cer /root/.acme.sh/$(hostname)_ecc/$(hostname).key
maddy recharge les certificats TLS à partir du disque une fois par minute afin de remarquer le renouvellement.
Première exécution du serveur Maddy
maddy lancera le /var/lib/maddy/répertoire et générera la clé DKIM.
Il est maintenant temps d'ajouter tous les enregistrements DNS nécessaires.
Ajoutez un enregistrement MX pour permettre mx1.example.orgde recevoir des e-mails :
example.org. MX 10 mx1.example.org.
Ajoutez un enregistrement SPF pour permettre aux serveurs de MX d'envoyer du courrier.
example.org. TXT "v=spf1 mx ~all"
Ajoutez un enregistrement DKIM . Cette clé est générée automatiquement par maddy dans le chemin de /var/lib/maddy/dkim_keys/example.org_default.dns.
default._domainkey.example.org. TXT "v=DKIM1; v=DKIM1; k=rsa; p=MIIB..."
Ajoutez un enregistrement DMARC pour définir la politique et le courrier de rapport.
_dmarc.example.org. TXT "v=DMARC1;p=quarantine;ruf=mailto:hi@example.org"
Marquez le domaine comme compatible MTA-STS et demandez des rapports sur les échecs.
_mta-sts.example.org. TXT "v=STSv1; id=1"
_smtp._tls.example.org. TXT "v=TLSRPTv1;rua=mailto:hi@example.org"
Enfin, enregistrez le fichier de stratégie MTA-STS dans le chemin /var/www/html/.well-known/mta-sts.txtavec le contenu suivant.
version: STSv1
mode: enforce
max_age: 604800
mx: mx1.example.org
La configuration du site Web nginx devrait ressembler à :
server {
listen 443 ssl;
listen [::]:443 ssl; # support ipv6, please
ssl_certificate /root/.acme.sh/mta-sts.example.org_ecc/fullchain.cer;
ssl_certificate_key /root/.acme.sh/mta-sts.example.org_ecc/mta-sts.example.org.key;
index index.html;
root /var/www/html;
server_name mta-sts.example.org;
location / {
try_files $uri $uri/ =404;
}
}
Rechargez nginx et nous pouvons obtenir le mta-sts.txt ci-dessus à partir de l'URL
https://mta-sts.example.org/.well-known/mta-sts.txt
Créez votre propre compte de messagerie.
Le maddy credsvous demandera de saisir le mot de passe du compte.
Activez enfin l'accès IMAP :
Les comptes de soumission SMTP et IMAP ne le sont hi@example.orgpas hi.
Dans le table.chain par défaut, seul le mail envoyé au compte existant sera accepté. Si vous souhaitez permettre de hi@example.orgrecevoir tous les envois vers une adresse inexistante, vous pouvez ajouter la ligne suivante au bloc table.chain local_rewrites.
optional_step regexp "(.+)@(.+)" "hi@$2"
Et la chaîne complète ressemblera à :
table.chain local_rewrites {
optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3"
optional_step static {
entry postmaster postmaster@$(primary_domain)
}
optional_step file /etc/maddy/aliases
optional_step regexp "(.+)@(.+)" "hi@$2"
}
La première règle transmettra l'envoi d'e-mails à foo+git@example.orgà foo@example.org. La seconde, assurez-vous que le destinataire du courrier adressé au postmaster (sans domaine) sera envoyé à postmaster@example.org. La troisième règle trouvera la règle de transfert à partir du fichier /let/maddy/aliases. Et la règle finale transmettra tous les courriers dont le destinataire est inconnu à hi@example.org.
Enfin, démarrez le service maddy.
Maddy écoutera les ports suivants :
Port |
Usage |
Sécurité |
25 |
MTA SMTP |
PLAIN/TLS |
465 |
Soumission SMTP |
TLS |
587 |
Soumission SMTP |
STARTTLS |
993 |
IMAP |
TLS |
143 |
IMAP |
STARTTLS |
Veuillez configurer le pare-feu pour autoriser le trafic sur ces ports.
S'il n'y a pas de problème, vous devez configurer votre client de messagerie et tester l'envoi et la réception. Je vous recommande d'utiliser mail-test.com pour vérifier s'il y a un problème avec votre configuration. S'il n'y a pas de problème évident, vous devez envoyer plusieurs courriers tests à un acteur majeur comme Gmail ou Outlook pour vérifier s'ils traitent votre courrier comme du spam.